From e378f9efff47f5fd661c6adb7abb7b214bc89648 Mon Sep 17 00:00:00 2001 From: robertl Date: Tue, 10 Sep 2002 02:11:06 +0000 Subject: [PATCH] Add microsoft pushpin 2002 support. Courtesy Alex Mottram. --- gpsbabel/Makefile | 3 +- gpsbabel/README | 16 ++ gpsbabel/psp.c | 339 ++++++++++++++++++++++++++++++++++++++ gpsbabel/reference/ps.psp | Bin 0 -> 964 bytes gpsbabel/testo | 5 + gpsbabel/vecs.c | 6 + 6 files changed, 368 insertions(+), 1 deletion(-) create mode 100644 gpsbabel/psp.c create mode 100644 gpsbabel/reference/ps.psp diff --git a/gpsbabel/Makefile b/gpsbabel/Makefile index fdb0587c5..9eeabe5bd 100644 --- a/gpsbabel/Makefile +++ b/gpsbabel/Makefile @@ -1,7 +1,8 @@ CFLAGS=-g -Icoldsync FMTS=magproto.o gpx.o geo.o gpsman.o mapsend.o mapsource.o \ - gpsutil.o tiger.o pcx.o csv.o cetus.o gpspilot.o magnav.o + gpsutil.o tiger.o pcx.o csv.o cetus.o gpspilot.o magnav.o \ + psp.o OBJS=main.o queue.o route.o waypt.o util.o vecs.o mkshort.o \ coldsync/util.o coldsync/pdb.o $(FMTS) diff --git a/gpsbabel/README b/gpsbabel/README index afff15b47..6c23b32ff 100644 --- a/gpsbabel/README +++ b/gpsbabel/README @@ -98,6 +98,22 @@ THE FORMATS by Ron Parker. GPSbabel can currently read gpspilot files, but not write them. + PSP + Microsoft's PocketStreets 2002 Pushpin (.PSP) format is not yet + completely documented. THE .PSP MODULE DOES NOT WORK WITH MS + STREETS & TRIPS 2002 .EST FILES. To create .PSP files from + Streets & Trips 2002, you will need to have PocketStreets support + installed. Please note that MS Streets & Trips only *EXPORTS* + .PSP files. It does not import them. MS Streets & Trips 2002 + only imports CSV files. To use .PSP files, simply copy them + over to the same folder on the mobile device as the map (.MPS), + and open PocketStreets. It should also be noted that in the case + a pushpin is outside of the exported map area, the pin will be + "grayed-out" and unused in PocketStreets. This is a good thing + as it allows us to create one big .PSP file that covers multiple + .MPS files. Unfortunately, you need one .PSP file for every + .MPS file. :( + COMMON USAGE diff --git a/gpsbabel/psp.c b/gpsbabel/psp.c new file mode 100644 index 000000000..19e8533f7 --- /dev/null +++ b/gpsbabel/psp.c @@ -0,0 +1,339 @@ +/* + PocketStreets 2002 Pushpin Files + Contributed to gpsbabel by Alex Mottram. + + Copyright (C) 2002 Robert Lipe, robertlipe@usa.net + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA + + */ + +#include "defs.h" + +#include +#include /* for M_PI */ + +/*#define _DEBUG_PSP 1*/ +#define MAXPSPSTRINGSIZE 256 +#define MAXPSPOUTPUTPINS 8192 /* Any more points than this is ludicrous */ + +static FILE *psp_file_in; +static FILE *psp_file_out; + +#ifdef _DEBUG_PSP +static void +dump_bufferstuff(char * header, char * buffer, int bufferlen) +{ + int i; + + printf("%s\n--------\n", header); + + for (i = 0 ; i < bufferlen ; i++) { + printf("%0.2X ", (unsigned char)buffer[i]); + } + printf("\n"); +} +#endif + +static char * +buffer_washer(char * buff, int buffer_len) +{ + int i; + + for (i = 0 ; i < buffer_len - 1; i++) { + if (buff[i] == '\0') { + memcpy(&buff[i], &buff[i+1], buffer_len - i); + buffer_len--; + buff[buffer_len] = '\0'; + } + } + + return (buff); +} + +static void +psp_rd_init(const char *fname) +{ + psp_file_in = fopen(fname, "r"); + if (psp_file_in == NULL) { + fatal("PSP: Cannot open %s for reading\n", fname); + } +} + +static void +psp_rd_deinit(void) +{ + fclose(psp_file_in); +} + +static void +psp_wr_init(const char *fname) +{ + psp_file_out = fopen(fname, "w"); + if (psp_file_out == NULL) { + fatal("PSP: Cannot open %s for writing\n", fname); + } +} + +static void +psp_wr_deinit(void) +{ + fclose(psp_file_out); +} + +static void +psp_read(void) +{ + char buff[MAXPSPSTRINGSIZE + 1]; + double radians; + waypoint *wpt_tmp; + int stringsize; + short int pincount; + + /* 32 bytes - file header */ + fread(&buff[0], 1, 32, psp_file_in); + + pincount = *(short int *)&buff[12]; + + while (pincount--) { + wpt_tmp = calloc(sizeof(*wpt_tmp),1); + + if (wpt_tmp == NULL) { + fatal("PSP: cannot allocate memory\n"); + } + + /* things we will probably never know about this waypoint */ + /* coming from a pushpin file. */ + + /* + wpt_tmp->creation_time; + wpt_tmp->position.altitude.altitude_meters; + wpt_tmp->url; + wpt_tmp->url_link_text; + wpt_tmp->icon_descr; TODO: map this. + */ + + /* 4 bytes at start of record */ + /* coming out of S&T, this 1st byte is probably the pin # (0x01, 0x02, etc...) */ + /* coming from pocketstreets, it's generally 0x00. Sometimes 0xC3. ? */ + + fread(&buff[0], 1, 4, psp_file_in); + + /* 1 byte, unkown */ + fread(&buff[0], 1, 1, psp_file_in); + + /* 8 bytes - latitude in radians */ + fread(&buff[0], 1, 8, psp_file_in); + radians = *(double *)&buff[0]; + wpt_tmp->position.latitude.degrees = (radians * 180.0) / M_PI; + + /* 8 bytes - longitude in radians */ + fread(&buff[0], 1, 8, psp_file_in); + radians = *(double *)&buff[0]; + wpt_tmp->position.longitude.degrees = (radians * 180.0) / M_PI; + + /* 1 byte - pin display properties */ + fread(&buff[0], 1, 1, psp_file_in); + + /* 3 bytes - unknown */ + fread(&buff[0], 1, 3, psp_file_in); + + /* 1 bytes - icon 0x00 - 0x27 */ + fread(&buff[0], 1, 1, psp_file_in); + + /* 3 bytes - unknown */ + fread(&buff[0], 1, 3, psp_file_in); + + /* 1 byte - string size */ + fread(&buff[0], 1, 1, psp_file_in); + + stringsize = buff[0]; + stringsize *= 2; + + if (stringsize > MAXPSPSTRINGSIZE) { + fatal("PSP: variable string size (%d) in PSP file exceeds MAX (%d).\n", stringsize, MAXPSPSTRINGSIZE); + } + + /* stringsize bytes - string data */ + fread(&buff[0], 1, stringsize, psp_file_in); + + buffer_washer(buff, stringsize); + +#ifdef _DEBUG_PSP + printf ("string1: [%s]\n", buff); +#endif + + wpt_tmp->shortname = strdup(buff); + + /* 1 bytes string size */ + fread(&buff[0], 1, 1, psp_file_in); + + stringsize = buff[0]; + stringsize *= 2; + + if (stringsize > MAXPSPSTRINGSIZE) { + fatal("PSP: variable string size (%d) in PSP file exceeds MAX (%d).\n", stringsize, MAXPSPSTRINGSIZE); + } + +#ifdef _DEBUG_PSP + printf ("string2: there are %d bytes to follow at offset %ld\n", stringsize, ftell(psp_file_in)); +#endif + + /* stringsize bytes - string data */ + fread(&buff[0], 1, stringsize, psp_file_in); + + buffer_washer(buff, stringsize); + +#ifdef _DEBUG_PSP + printf ("string2: [%s]\n", buff); +#endif + wpt_tmp->description = strdup(buff); + + /* 1 bytes - string size */ + fread(&buff[0], 1, 1, psp_file_in); + + stringsize = buff[0]; + stringsize *= 2; + + if (stringsize > MAXPSPSTRINGSIZE) { + fatal("PSP: variable string size (%d) in PSP file exceeds MAX (%d).\n", stringsize, MAXPSPSTRINGSIZE); + } + + +#ifdef _DEBUG_PSP + printf ("string: there are %d bytes to follow at offset %ld\n", stringsize, ftell(psp_file_in)); +#endif + + /* stringsize bytes - string data (address?) */ + fread(&buff[0], 1, stringsize, psp_file_in); + + buffer_washer(buff, stringsize); + +#ifdef _DEBUG_PSP + printf ("string3: [%s]\n", buff); +#endif + + waypt_add(wpt_tmp); + } + + +} + +static void +psp_disp(waypoint *wpt) +{ + double lon, lat; + char tbuf[64]; + char c; + int i; + + /* convert lat/long back to radians */ + lat = (wpt->position.latitude.degrees * M_PI) / 180.0; + lon = (wpt->position.longitude.degrees * M_PI) / 180.0; + + /* 4 leading bytes */ + memset(&tbuf, '\0', sizeof(tbuf)); + fwrite(&tbuf, 1, 4, psp_file_out); + + /* my test files seem to always have this byte as 0x03, */ + /* although nothing seems to really care. */ + c = 0x03; + + /* 1 unknown bytes */ + fwrite(&c, 1, 1, psp_file_out); + + /* 8 bytes - latitude/radians */ + fwrite(&lat, 1, 8, psp_file_out); + + /* 8 bytes - longitude/radians */ + fwrite(&lon, 1, 8, psp_file_out); + + /* 1 byte - pin properties */ + c = 0x14; /* display pin on! display notes on! */ + fwrite(&c, 1, 1, psp_file_out); + + memset(&tbuf, '\0', sizeof(tbuf)); + + /* 3 unknown bytes */ + fwrite(&tbuf, 1, 3, psp_file_out); + + /* 1 icon byte 0x00 = PIN */ + fwrite(&tbuf, 1, 1, psp_file_out); + + /* 3 unknown bytes */ + fwrite(&tbuf, 1, 3, psp_file_out); /* 3 junk */ + + c = strlen(wpt->shortname); + /* 1 string size */ + fwrite(&c, 1, 1, psp_file_out); + + for (i = 0 ; wpt->shortname[i] ; i++) { + fwrite(&wpt->shortname[i], 1, 1, psp_file_out); /* char */ + fwrite(&tbuf[0], 1, 1, psp_file_out); /* null */ + } + + /* 1 byte string size */ + c = strlen(wpt->description); + fwrite(&c, 1, 1, psp_file_out); + + for (i = 0 ; wpt->description[i] ; i++) { + fwrite(&wpt->description[i], 1, 1, psp_file_out); /* char */ + fwrite(&tbuf[0], 1, 1, psp_file_out); /* null */ + } + + /* just for the hell of it, we'll scrap the third string. */ + c = strlen(tbuf); + /* 1 byte string size */ + fwrite(&c, 1, 1, psp_file_out); + + for (i = 0 ; tbuf[i] ; i++) { + fwrite(&tbuf[i], 1, 1, psp_file_out); /* char */ + fwrite(&tbuf[0], 1, 1, psp_file_out); /* null */ + } + +} + +static void +psp_write(void) +{ + short int s; + unsigned char header_bytes[] = { 0x31, 0x6E, 0x69, 0x50, 0x20, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + + /* the header: */ + /* 31 6E 69 50 20 00 00 00 08 00 00 00 11 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 */ + /* offset 0x0C - 0x0D = 2 byte pin count */ + + s = waypt_count(); + + if (s > MAXPSPOUTPUTPINS) { + fatal("attempt to output too many pushpins (%d). The max is %d. Sorry.\n", s, MAXPSPOUTPUTPINS); + } + + /* insert waypoint count into header */ + memcpy(&header_bytes[12], &s, 2); + + fwrite(&header_bytes, 1, 32, psp_file_out); + + waypt_disp_all(psp_disp); +} + +ff_vecs_t psp_vecs = { + psp_rd_init, + psp_wr_init, + psp_rd_deinit, + psp_wr_deinit, + psp_read, + psp_write, +}; diff --git a/gpsbabel/reference/ps.psp b/gpsbabel/reference/ps.psp new file mode 100644 index 0000000000000000000000000000000000000000..4685ec58f774f8ea4d212d519374d58634cce568 GIT binary patch literal 964 zcmXra%M4IpU|`??Voo5&2ADkxLoVryKe6}BcGFc2{jpyJs*2T}!I{C8!3hWzd>Qf? zN*VGPN*EFuGJ&)LP%x7rn;{j*@&J;F3}rwPB%Z`j2_%bws*8avLk43o1{=v7nUl3f zP2-8ZLeAIR*(L~^*g!TJGB^Sin={CVFl2zu4Pht(+L{A|FjEtOiYyq67z%)P=K$qO zfHG=8>;|+y7c5o@aXa&Z>nkrTlX_ym{l}x-(FPbcIRg!GVvuzK>H)bMhTc!FFXr!^s)QONPc4#GYWR@xHX- z$gADzPwefF&U^dP7R_v91_NLyxiQEE15K)APzSrw100)(n0Ev6i-5L*Xow#{G35&M zcRDZ_jG?h^bY4n4L-~olc=*2h)6N+77y|v^$RO_yG@}FvD;Yw8DG8RgkYigPC>jp* zTM^KFNQwvm^Rj_%gQVmspWPMMfIhl=NKS*@39C&m3`(9r{W)+KgYr!}>GlBtGSjj- literal 0 HcmV?d00001 diff --git a/gpsbabel/testo b/gpsbabel/testo index 73a7dedae..0bcc451af 100755 --- a/gpsbabel/testo +++ b/gpsbabel/testo @@ -54,3 +54,8 @@ diff /tmp/mm.gps /tmp/gu.wpt ${PNAME} -i magellan -f reference/magfile -o magellan -F /tmp/magfile diff /tmp/magfile reference/magfile + +# PSP (PocketStreets 2002 Pushpin (.PSP)) file format +${PNAME} -i geo -f geocaching.loc -o psp -F /tmp/ps.psp +diff /tmp/ps.psp reference + diff --git a/gpsbabel/vecs.c b/gpsbabel/vecs.c index e415193ae..ac044a449 100644 --- a/gpsbabel/vecs.c +++ b/gpsbabel/vecs.c @@ -40,6 +40,7 @@ extern ff_vecs_t pcx_vecs; extern ff_vecs_t csv_vecs; extern ff_vecs_t cetus_vecs; extern ff_vecs_t gpspilot_vecs; +extern ff_vecs_t psp_vecs; static vecs_t vec_list[] = { @@ -93,6 +94,11 @@ vecs_t vec_list[] = { "csv", "Comma separated values" }, + { + &psp_vecs, + "psp", + "MS PocketStreets 2002 Pushpin" + }, { &cetus_vecs, "cetus", -- 2.30.2